
#import "ToMPEG.h"
#include <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <ctype.h>
     #include <sys/file.h>  /* POSIX applications #include <unistd.h> */

     #define R_OK    4/* test for read permission */
     #define W_OK    2/* test for write permission */
     #define X_OK    1/* test for execute (search) permission */
     #define F_OK    0/* test for presence of file */

     int access(const char *path, int mode);

@implementation ToMPEG

#define	ANIMDIRECTORY		"~/Library/Images/Movies/Globe.anim"
#define STARTFRAME		1
#define ENDFRAME		72
#define PBMPLUSDIRECTORY 	"/usr/local/pbmplus/bin"
#define FRAMEWIDTHxHEIGHT 	"640x480"
#define SPECIALFRAMETYPE	"MyType"
/*  The following are the tags set in InterfaceBuilder for the "formatButton" PopUp */
#define TIFF		0
#define GIF		1
#define	GOULD		2
#define	ILBM		3
#define	IMG		4
#define	MTV		5
#define	PCX		6
#define	PGM		7
#define	PI1		8
#define	PICT		9
#define	PJ		10
#define	QRT		11
#define	RAW		12
#define	RGB3		13
#define	SLD		14
#define	SPC		15
#define	SPU		16
#define	TGA		17
#define	XIM		18
#define	XPM		19
#define	YUV		20
#define PPM		21
#define SPECIAL		22

char MPEGer[MAXPATHLEN + 1] = "mpeg-encode";
char PPMer[MAXPATHLEN + 1]  = "tiff2ppm";
char converter[MAXPATHLEN + 1] = "giftoppm";
char MyConverter[MAXPATHLEN + 1]  = "MyType2ppm";

/*  extract the name of the animation from the full pathname */
char *stripname(char *animdirectory)
{
	char *tmp, *tmp2, *tmp3;
	tmp = (char *)malloc(100);
	strcpy(tmp, animdirectory);
	if((tmp2 = strrchr(tmp, '.'))) (*tmp2) = '\0';
	if((tmp3 = strrchr(tmp, '/'))) return (tmp3 + 1);
	else return tmp;
}

/*  This method gets called automatically, since toMPEG is App's delegate	*/
char *param[19];
- appDidInit:sender
{
	NXBundle *bundle;
	int i;
	
/*  Initialize pathnames to appwrapper resources: mpeg-encode and tiff2ppm	*/
	bundle = [NXBundle bundleForClass:[self class]];
	[bundle getPath:MPEGer forResource:"mpeg-encode" ofType:NULL];
	[bundle getPath:PPMer forResource:"tiff2ppm" ofType:NULL];


/*  Initialize the param strings						*/
	for(i=0; i<19; i++) param[i] = (char *)malloc(125);
	strcpy(param[0], "PATTERN		IBBPBBPBBPBBPBB");
	strcpy(param[1], "OUTPUT		Globe.mpg");
	strcpy(param[2], "GOP_SIZE	40");
	strcpy(param[3], "SLICES_PER_FRAME	1");
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	sprintf(param[5], "INPUT_CONVERT	  %s *", PPMer);
	strcpy(param[6], "INPUT_DIR	~/Library/Images/Movies/Globe.anim");
	strcpy(param[7], "INPUT");
	strcpy(param[8], "Globe.*.tiff	[1-72]");
	strcpy(param[9], "END_INPUT");
	strcpy(param[10], "PIXEL		HALF");
	strcpy(param[11], "RANGE		10");
	strcpy(param[12], "PSEARCH_ALG	LOGARITHMIC");
	strcpy(param[13], "BSEARCH_ALG	CROSS2");
	strcpy(param[14], "IQSCALE		8");
	strcpy(param[15], "PQSCALE		10");
	strcpy(param[16], "BQSCALE		25");
	strcpy(param[17], "REFERENCE_FRAME	ORIGINAL");
	strcpy(param[18], "FORCE_ENCODE_LAST_FRAME");

/*  Initialize outlets to the List and the Matrix of the "formatButton" PopUp	*/
	if (![formatButton isKindOf:[PopUpList class]]) 
	{
		formatList = [formatButton target];
		formatMatrix = [formatList itemList];
	}

	[converterinfo setEnabled:NO];

	return self;
}

- setDefaults:sender
{
/* initialize animinfo form with default values  */
	[animinfo setStringValue:ANIMDIRECTORY at:0];
	[animinfo setIntValue:STARTFRAME at:1];
	[animinfo setIntValue:ENDFRAME at:2];
/* initialize formatButton and its matrix of MenuCells with default value */
	sprintf(param[5], "INPUT_CONVERT	%s *", PPMer);
	[formatButton setTitle: "TIFF"];
	[formatMatrix selectCellWithTag:TIFF];
	[converterinfo setEnabled:NO];
	[converterinfo setTitle:"pbmplus Directory:" at:0];
	[converterinfo setStringValue:PBMPLUSDIRECTORY at:0];
	return self;
}

- setConverterInfo
{
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	[converterinfo setTitle:"pbmplus Directory:" at:0];
	[converterinfo setStringValue:PBMPLUSDIRECTORY at:0];
	[converterinfo setEnabled:YES];
	return self;
}



- doTIFF:sender
{
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	sprintf(param[5], "INPUT_CONVERT	%s *", PPMer);
	[converterinfo setEnabled:NO];
	return self;
}

- doGIF:sender
{
	strcpy(converter, "giftoppm");
	[self setConverterInfo];
	return self;
}

- doGOULD:sender
{
	strcpy(converter, "gouldtoppm");
	[self setConverterInfo];
	return self;
}

- doILBM:sender
{
	strcpy(converter, "ilbmtoppm");
	[self setConverterInfo];
	return self;
}

- doIMG:sender
{
	strcpy(converter, "imgtoppm");
	[self setConverterInfo];
	return self;
}

- doMTV:sender
{
	strcpy(converter, "mtvtoppm");
	[self setConverterInfo];
	return self;
}

- doPCX:sender
{
	strcpy(converter, "pcxtoppm");
	[self setConverterInfo];
	return self;
}

- doPGM:sender
{
	strcpy(converter, "pgmtoppm");
	[self setConverterInfo];
	return self;
}

- doPI1:sender
{
	strcpy(converter, "pi1toppm");
	[self setConverterInfo];
	return self;
}

- doPICT:sender
{
	strcpy(converter, "picttoppm");
	[self setConverterInfo];
	return self;
}

- doPJ:sender
{
	strcpy(converter, "pjtoppm");
	[self setConverterInfo];
	return self;
}

- doQRT:sender
{
	strcpy(converter, "qrttoppm");
	[self setConverterInfo];
	return self;
}

- doRAW:sender
{
	strcpy(converter, "rawtoppm");
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	sprintf(param[5], "INPUT_CONVERT	%s/%s ", 
		[converterinfo stringValueAt:0], converter);
	[converterinfo setTitle:"WIDTHxHEIGHT:" at:0];
	[converterinfo setStringValue:FRAMEWIDTHxHEIGHT at:0];
	[converterinfo setEnabled:YES];
	return self;
}

- doRGB3:sender
{
	strcpy(converter, "rgb3toppm");
	[self setConverterInfo];
	return self;
}

- doSLD:sender
{
	strcpy(converter, "sldtoppm");
	[self setConverterInfo];
	return self;
}

- doSPC:sender
{
	strcpy(converter, "spctoppm");
	[self setConverterInfo];
	return self;
}

- doSPU:sender
{
	strcpy(converter, "sputoppm");
	[self setConverterInfo];
	return self;
}

- doTGA:sender
{
 	strcpy(converter, "tgatoppm");
	[self setConverterInfo];
	return self;
}

- doXIM:sender
{
	strcpy(converter, "ximtoppm");
	[self setConverterInfo];
	return self;
}

- doXPM:sender
{
	strcpy(converter, "xpmtoppm");
	[self setConverterInfo];
	return self;
}

- doYUV:sender
{
	strcpy(param[4], "BASE_FILE_FORMAT	YUV\nYUV_SIZE	");
 	strcpy(param[5], "INPUT_CONVERT	*");
	[converterinfo setTitle:"WIDTHxHEIGHT:" at:0];
	[converterinfo setStringValue:FRAMEWIDTHxHEIGHT at:0];
	[converterinfo setEnabled:YES];
	return self;
}

- doPPM:sender
{
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	strcpy(param[5], "INPUT_CONVERT	*");
	[converterinfo setEnabled:NO];
	return self;
}

- doSPECIAL:sender
{
	strcpy(param[4], "BASE_FILE_FORMAT	PPM");
	[converterinfo setTitle:"FrameType:" at:0];
	[converterinfo setStringValue: SPECIALFRAMETYPE at:0];
	[converterinfo setEnabled:YES];
	return self;
}

- toMPEGMethod:sender
{
	char *tmp, *animdirectory, *moviename, *moviepath, *frametype; 
	char *fullpath, *framefile; 
	char *paramfile, *resultfile, *execstring;
	int startframe, endframe, numframes, i, width, height, exit_status;
	FILE *pfile;

	animdirectory = (char *)malloc(100);
	moviepath = (char *)malloc(100);
	frametype = (char *)malloc(100);
	fullpath = (char *)malloc(200);
	framefile = (char *)malloc(300);
	paramfile = (char *)malloc(100);
	resultfile = (char *)malloc(100);
	execstring = (char *)malloc(100);

/* store user's table entries into variables	 */

	strcpy(animdirectory, [animinfo stringValueAt:0]);
	startframe = [animinfo intValueAt:1];
	endframe = [animinfo intValueAt:2];
	
	sprintf(param[6], "INPUT_DIR	%s", animdirectory);
	numframes = endframe - startframe + 1;
	sprintf(param[2], "GOP_SIZE	%d", numframes);

	moviename = stripname(animdirectory);
	strcpy(moviepath, "/tmp/");
	sprintf(param[1], "OUTPUT	%s%s.mpg", moviepath, moviename);

	strcpy(frametype, [formatButton title]);
	tmp = frametype; do *tmp = tolower(*tmp); while(*tmp++);
	switch([[formatMatrix selectedCell] tag]) {
		case YUV:
			sprintf(param[8], "%s.*.%s	[%d-%d]", 
				moviename, frametype, startframe, endframe);
			strcat(param[4], [converterinfo stringValueAt:0]);
			break;
		case RGB3:
			sprintf(param[8], "%s.*	[%d-%d]", 
				moviename, startframe, endframe);
			sprintf(param[5], "INPUT_CONVERT	%s/%s *.r *.g *.b", 
				[converterinfo stringValueAt:0], converter);
			break;
		case RAW:
			sprintf(param[8], "%s.*.%s	[%d-%d]", 
				moviename, frametype, startframe, endframe);
			width = atoi((tmp = [converterinfo stringValueAt:0]));
			height = atoi(strpbrk(tmp, "xX") + 1);
			sprintf(param[5], "%s %d %d *", param[5], width, height);
			break;
		case SPECIAL:
			strcpy(frametype, [converterinfo stringValueAt:0]);
			sprintf(param[8], "%s.*.%s	[%d-%d]", 
				moviename, frametype, startframe, endframe);
			strcpy(MyConverter, PPMer);
			*(strrchr(MyConverter, '/') + 1) = '\0';
			strcat(MyConverter, frametype);
			sprintf(param[5], "INPUT_CONVERT	%s2ppm *", MyConverter);
			break;
		default: 
			sprintf(param[8], "%s.*.%s	[%d-%d]", 
				moviename, frametype, startframe, endframe);
			if([converterinfo isEnabled]) {
				sprintf(param[5], "INPUT_CONVERT	%s/%s *", 
					[converterinfo stringValueAt:0], converter);
			}
			break;
	}

	
	if(*animdirectory == '~') {
		strcpy(fullpath, NXHomeDirectory());
		strcat(fullpath, animdirectory + 1);
	}
	else strcpy(fullpath, animdirectory);

/* check that the FIRST frame file exists      */
	sprintf(framefile, "%s/%s.%d.%s", 
			fullpath, moviename, startframe, frametype);
	if(access(framefile, R_OK)) {
		NXRunAlertPanel("Cannot read file!", "First frame %s not accessible!",
			"OK",NULL,NULL,
			framefile);
		return self;
	}
/* check that the LAST frame file exists      */
	sprintf(framefile, "%s/%s.%d.%s", 
			fullpath, moviename, endframe, frametype);
	if(access(framefile, R_OK)) {
		NXRunAlertPanel("Cannot read file!", "Last frame %s not accessible!",
			"OK",NULL,NULL,
			framefile);
		return self;
	}


/* create the parameter file on /tmp	       */
	strcpy(paramfile, "/tmp/");
	strcat(strcat(paramfile, moviename), ".param");
	pfile = fopen(paramfile, "w");
	for(i=0; i<19; i++) fprintf(pfile, "%s\n", param[i]);
	fclose(pfile);

/* execute "mpeg-encode paramfile > resultfile"	       */
	strcpy(resultfile, "/tmp/");
	strcat(strcat(resultfile, moviename), ".result");
	sprintf(execstring, "%s %s > %s &", MPEGer, paramfile, resultfile);
	if(!(exit_status = system(execstring)))
		NXRunAlertPanel("Submitted MPEG Job to sh",
"Parameters: %s\nStatistics: %s\nMPEG: %s%s.mpg\nAny errors are listed in the console.",
		"OK",NULL,NULL,
		 paramfile, resultfile, moviepath, moviename);
	else 	NXRunAlertPanel("sh reports problem with MPEG Job!",
		"Errors are listed in the console.",
		"OK",NULL,NULL);

    return self;
}


@end
